﻿using Sustainalytics.ClientDW.Entities;
using Sustainalytics.DataLayer.EsgRatings;
using Sustainalytics.DataLayer.Shared;
using Sustainalytics.Entities.ESGRatings;
using Sustainalytics.ESG.Entities;
using Sustainalytics.MongoDB.Extensions;
using Sustainalytics.Utils;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using RPESGResearchState = Sustainalytics.ESG.Entities.RPESGResearchState;

namespace Sustainalytics.ReportGenerator.BL
{
    public class ReportDataPreparationBulkReader
    {
        private readonly int _bulkSize;
        private readonly string _clientDwUrl;
        private readonly CancellationToken _cancelToken;
        private readonly int _maxDegreeOfParallelism;

        public ReportDataPreparationBulkReader(int bulkSize, IEnumerable<Guid> ids, string clientDwUrl, string dwArchiveUrl, ESGProfile defaultEsgProfile, ConcurrentBag<string> log, CancellationToken cancelToken, int maxDegreeOfParallelism = -1)
        {
            _bulkSize = bulkSize;
            _clientDwUrl = clientDwUrl;

            AllFinancialData = new Dictionary<Guid, FinancialData>();
            IndicatorTemplates = new List<IndicatorTemplate>();
            SubPeerGroupKeyEsgIssueDictionary = new Dictionary<int, List<SubPeerGroupKeyEsgIssue>>();

            _esgDefaultProfile = defaultEsgProfile;

            _cancelToken = cancelToken;
            _maxDegreeOfParallelism = maxDegreeOfParallelism;

            if (_maxDegreeOfParallelism < 1)
                _maxDegreeOfParallelism = ParallelHelper.GetMaxDegreeOfParallelism();
        }

        public Dictionary<Guid, Analyst> AnalystsDictionary { get; set; }
        public Dictionary<Guid, FinancialData> AllFinancialData { get; set; }
        public IList<IndicatorTemplate> IndicatorTemplates { get; set; }
        public Dictionary<int, List<SubPeerGroupKeyEsgIssue>> SubPeerGroupKeyEsgIssueDictionary { get; set; }
        private ESGProfile _esgDefaultProfile { get; set; }

        public void OneTimeDataRead(Guid matrixId, Guid? accountId, Guid? profileGuid)
        {
            // one time reading collections
            var readActions = new List<Action>();
            readActions.Add(() =>
            {

                var corporateDataBl = new CorporateDataManagement(MongoFactory.GetCollectionFromDatabase<CorporateData>(_clientDwUrl), MongoFactory.GetCollectionFromDatabase<RPESGResearchState>(_clientDwUrl));
                var corporateData = corporateDataBl.GetFilteredCompaniesWithEsgResearchAsync(null, null, accountId, profileGuid, matrixId).Result;
                var allIds = corporateData.Select(x => x.Id);
                var financialDataRep = new RepositoryCollection<FinancialData>(_clientDwUrl);
                AllFinancialData.Clear();

                var position = 0;
                for (; ; )
                {
                    var ids = allIds.Skip(position).Take(_bulkSize);
                    position += _bulkSize;
                    var dictionary = financialDataRep.ReadbyIds(ids, new string[] { "MarketCapitalization", "CompanyName" });
                    if (dictionary != null)
                    {
                        foreach (var x in dictionary.Values)
                            AllFinancialData[x.Id] = x;
                    }

                    if (ids.Count() < _bulkSize || (ids.Count() == _bulkSize && _bulkSize == 1))
                        break;
                }
            });


            readActions.Add(() =>
            {
                var rep = new RepositoryCollection<IndicatorTemplate>(_clientDwUrl);
                IndicatorTemplates = rep.ReadAll();
            });

            readActions.Add(() =>
            {
                // analyst 
                var analystRepo = new RepositoryCollection<Analyst>(_clientDwUrl);
                AnalystsDictionary = analystRepo.ReadAll()
                                                .ToDictionary(k => k.Id, v => v);
            });

            readActions.Add(() =>
            {
                var rep = new RepositoryCollection<SubPeerGroupKeyEsgIssue>(_clientDwUrl);
                var all = rep.ReadAll();

                if (all == null)
                    return;

                var list = all.GroupBy(x => x.SubPeerGroupId).ToList();
                list.ForEach(x => SubPeerGroupKeyEsgIssueDictionary.Add(x.Key, x.ToList()));
            });

            readActions.RunInParallel(_cancelToken, _maxDegreeOfParallelism);
        }
    }
}
